package com.uam.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.uam.common.config.UAMConfig;
import com.uam.common.constant.CST;
import com.uam.common.exception.CustomException;
import com.uam.db.mapper.AircraftMapper;
import com.uam.db.mapper.PointMapper;
import com.uam.db.mapper.TaskMapper;
import com.uam.db.model.dto.TaskListDTO;
import com.uam.db.model.entity.Aircraft;
import com.uam.db.model.entity.Point;
import com.uam.db.model.entity.Task;

import com.uam.db.model.vo.TaskVO;
import com.uam.service.AircraftService;
import com.uam.service.PointService;
import com.uam.service.TaskService;
import com.uam.utils.*;
import com.uam.web.common.model.PageRes;
import com.uam.web.common.model.Result;
import com.uam.web.common.utils.FileUploadUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;

/**
 * @author uam
 * @create 2023/12/3 17:22
 * @email uam@uam.com
 */
@Service
@Slf4j
public class TaskServiceImpl implements TaskService {
    @Autowired
    private TaskMapper taskMapper;
    @Autowired
    private PointMapper pointMapper;
    @Autowired
    private UAMConfig uamConfig;
    @Autowired
    private PointService pointService;
    @Autowired
    private AircraftService aircraftService;
    @Autowired
    private AircraftMapper aircraftMapper;
    @Autowired
    private RedisUtil redisUtil;

    @Override
    public Result create(HttpServletRequest request, String taskName, Long airplaneId, String startTime,
                         Long startPoint, Long destination,
                         Integer mode, List<Long> transitPoints, String  rectanglePoint) {
        Task task = new Task();
        task.setName(taskName);
        task.setAircraftId(Math.toIntExact(airplaneId));
        LambdaQueryWrapper<Aircraft> aircraftQueryWrapper = new LambdaQueryWrapper<>();

        aircraftQueryWrapper.eq(Aircraft::getAirplaneId, Math.toIntExact(airplaneId));
        Aircraft aircraft = aircraftMapper.selectOne(aircraftQueryWrapper);
        if (aircraft == null) {
            throw new CustomException("飞行器id不存在");
        }
        task.setStartTime(TimeUtils.getLocalDateTime(startTime.trim()));
        if (mode < 0 || mode > 4) {
            throw new CustomException("mode错误");
        }
        task.setMode(mode);
        task.setCreateTime(LocalDateTime.now());
        task.setUpdateTime(LocalDateTime.now());
        task.setSetttings(getSettingsForPointList(getPointList(startPoint, destination, transitPoints)));
        String loginNameForToken = TokenUtils.getLoginNameForToken(request);
        Long userIdForToken = TokenUtils.getUserIdForToken(request);
        task.setAuthorName(loginNameForToken);
        task.setAuthorId(Math.toIntExact(userIdForToken));
        task.setStartId(startPoint);
        task.setDestinationId(destination);
        task.setRectanglePoint(rectanglePoint);
        taskMapper.insert(task);
        return Result.createSuccess("创建任务成功");
    }

    @Override
    public Result selectTaskList(Integer pageNum, Integer pageSize, List<Integer> status, String taskName, String createLoginName) {
        if (CollectionUtils.isEmpty(status)) {
            return Result.createSuccess(new PageRes<>(new ArrayList<TaskListDTO>(), 0));
        }
        Page<TaskListDTO> page = new Page<>(pageNum, pageSize);
        IPage<TaskListDTO> iPage = taskMapper.selectTaskList(page, status, taskName, createLoginName);
        PageRes<TaskListDTO> taskListDTOPageRes = new PageRes<>(iPage.getRecords(), iPage.getTotal());
        return Result.createSuccess(taskListDTOPageRes);
    }

    @Override
    public Result uploadTaskFile(HttpServletRequest request, MultipartFile file) {
        try {
            String fileUrl = FileUploadUtils.upload(uamConfig.getUploadpath(), file, new String[]{"csv"});
            HashMap<String, String> res = new HashMap<>();
            res.put("fileUrl", fileUrl);
            return Result.createSuccess(res);

        } catch (IOException e) {
            throw new CustomException("文件上传失败");
        }
    }

    @Override
    public Result verify(HttpServletRequest request, String fileUrl) {

        List<String> strings = CSVReader.readCSV2List(fileUrl);
        Map<String, Object> stringObjectMap = string2Task(request, strings);
        return Result.createSuccess(stringObjectMap);
    }

    @Override
    public Result createBatch(HttpServletRequest request, String redisKey,String rectanglePoint) {
        Long userIdForToken = TokenUtils.getUserIdForToken(request);
        List<Task> tasks = (List<Task>) redisUtil.get("batch:" + userIdForToken);
        AtomicReference<Integer> success = new AtomicReference<>(0);
        tasks.forEach(task -> {
            task.setRectanglePoint(rectanglePoint);
            taskMapper.insert(task);
            success.getAndSet(success.get() + 1);
        });

        return Result.createSuccess("创建成功", success.get());
    }

    @Override
    public Result edit(Integer taskId, Integer status, String startTime) {

        UpdateWrapper<Task> taskUpdateWrapper = new UpdateWrapper<>();
        taskUpdateWrapper.eq("ID", taskId);
        taskUpdateWrapper.set("STATUS", status);
        if (StringUtils.isNotEmpty(startTime)) {
            taskUpdateWrapper.set("START_TIME", TimeUtils.getLocalDateTime(startTime.trim()));
        } else {
            taskUpdateWrapper.set("START_TIME", LocalDateTime.now().plus(Duration.ofMinutes(5)));
        }
        int update = taskMapper.update(null, taskUpdateWrapper);

        return Result.createSuccess("编辑成功", update);
    }

    @Override
    public void export(HttpServletResponse response, String startTime, String endTime) {
        LambdaQueryWrapper<Task> taskLambdaQueryWrapper = new LambdaQueryWrapper<>();
        LocalDateTime start;
        LocalDateTime end = null;
        if (StringUtils.isNotEmpty(startTime)) {
            start = TimeUtils.getLocalDateTime(startTime.trim());
        } else {
            start = LocalDateTime.now().minus(14, ChronoUnit.DAYS);
        }
        if (StringUtils.isNotEmpty(endTime)) {
            end = TimeUtils.getLocalDateTime(endTime.trim());
        } else {
            end = LocalDateTime.now();
        }
        taskLambdaQueryWrapper.between(Task::getCreateTime, start, end);
        // taskLambdaQueryWrapper.last("limit 200");
        // taskLambdaQueryWrapper.eq(Task::getId,259);
        List<Task> tasks = taskMapper.selectList(taskLambdaQueryWrapper);
        List<TaskVO> taskVoList = getTaskVoList(tasks);
     /*   for (int i = 0; i < 11; i++) {
            taskVoList.add(taskVoList.get(0));
        }*/
        try {
            // CsvUtil.createCsvFile(taskVoList, null, "export_" + System.currentTimeMillis(), response);
            CsvUtil.createJSONFile(taskVoList, null, "export_" + System.currentTimeMillis(), response);
        } catch (Exception e) {
            throw new CustomException("导出异常");
        }
    }


    private List<Point> getPointList(Long startPoint, Long destination, List<Long> transitPoints) {
        LambdaQueryWrapper<Point> pointLambdaQueryWrapper = new LambdaQueryWrapper<>();
        pointLambdaQueryWrapper.eq(Point::getPointId, startPoint);
        List<Point> res = new ArrayList<>();
        Point start = pointMapper.selectOne(pointLambdaQueryWrapper);
        if (null == start) {
            throw new CustomException("出发点Id不存在");
        }
        pointLambdaQueryWrapper.clear();
        pointLambdaQueryWrapper.eq(Point::getPointId, destination);
        Point dest = pointMapper.selectOne(pointLambdaQueryWrapper);
        if (null == dest) {
            throw new CustomException("目的地Id不存在");
        }
        res.add(start);
        if (CollectionUtils.isNotEmpty(transitPoints)) {
            transitPoints.forEach(trs -> {
                pointLambdaQueryWrapper.clear();
                pointLambdaQueryWrapper.eq(Point::getPointId, trs);
                Point point = pointMapper.selectOne(pointLambdaQueryWrapper);
                if (point == null) {
                    throw new CustomException("途经点地Id不存在 id:" + trs);
                }
                res.add(point);
            });
        }

        res.add(dest);
        return res;
    }

    private String getSettingsForPointList(List<Point> list) {
        JSONArray jsonArray = new JSONArray();
        list.forEach(point -> {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("id", point.getPointId());
            jsonObject.put("name", point.getPointName());
            JSONArray positionJA = new JSONArray();
            String position = point.getPosition();
            String[] split = position.split(",");
            for (String s : split) {
                positionJA.add(Float.valueOf(s));
            }
            jsonObject.put("position", positionJA);
            jsonArray.add(jsonObject);

        });
        return jsonArray.toString();
    }

    private Map<String, Object> string2Task(HttpServletRequest request, List<String> lines) {
        HashMap<String, Object> res = new HashMap<>();
        List<Task> tasks = new ArrayList<>();
        String loginNameForToken = TokenUtils.getLoginNameForToken(request);
        Long userIdForToken = TokenUtils.getUserIdForToken(request);
        AtomicReference<Integer> success = new AtomicReference<>(0);
        AtomicReference<Integer> fail = new AtomicReference<>(0);
        a:
        for (String line : lines) {
            String[] split = line.split(",");
            if (split.length != 7) {
                fail.getAndSet(fail.get() + 1);
                continue a;
            }
            String s = split[0].replace("\uFEFF", "");
            if (StringUtils.isEmpty(s)) {
                continue a;
            }

            byte[] bytes = s.getBytes(StandardCharsets.UTF_8);

            if (s.startsWith("任务名称") || s.contains("start")) {
                continue a;
            } else {

                String taskName = split[0].trim().replaceAll("\"", "");
                String airplaneName = split[1].trim().replaceAll("\"", "");
                String startPointName = split[2].trim().replaceAll("\"", "");
                String transitPointNames = split[3].trim().replaceAll("\"", "");
                String[] names = transitPointNames.trim().replaceAll("\"", "").split("\\|");
                String destinationName = split[4].trim().replaceAll("\"", "");
                String startTimeStr = split[5].trim().replaceAll("\"", "");
                String modeStr = split[6].trim().replaceAll("\"", "");
                List<String> pointNames = new ArrayList<>();
                pointNames.add(startPointName);
                pointNames.addAll(Arrays.asList(names));
                pointNames.add(destinationName);
                List<Point> pointlist = new ArrayList<>();
                b:
                for (String name : pointNames) {

                    if ("".equals(name) || name == null) {
                        continue;
                    }

                    Result list = pointService.list(0, 1, name);
                    PageRes<Point> pointPageRes = (PageRes<Point>) list.getData();
                    List<Point> rows = pointPageRes.getRows();
                    if (CollectionUtils.isEmpty(rows)) {//
                        fail.getAndSet(fail.get() + 1);
                        continue a;
                    } else {
                        pointlist.add(rows.get(0));
                    }

                }
                Result list1 = aircraftService.list(0, Integer.MAX_VALUE, airplaneName, null, -1);
                PageRes<Aircraft> aircraftPageRes = (PageRes<Aircraft>) list1.getData();
                List<Aircraft> aircrafts = aircraftPageRes.getRows();
                if (CollectionUtils.isEmpty(aircrafts)) {
                    fail.getAndSet(fail.get() + 1);
                    log.info("飞行器名称不存在，{}", airplaneName);
                    continue a;
                }
                Task task = new Task();
                taskName = StringUtils.isEmpty(taskName) ? "默认名称_" + System.currentTimeMillis() : taskName;
                Long airplaneId = aircrafts.get(0).getAirplaneId();
                String settingsForPointList = getSettingsForPointList(pointlist);
                Long startId = pointlist.get(0).getPointId();
                Long destinationId = pointlist.get(pointlist.size() - 1).getPointId();
                LocalDateTime startTime = TimeUtils.getLocalDateTime(startTimeStr.trim());
                Integer mode = Integer.valueOf(modeStr);
                if (mode < 0 || mode > 4) {
                    fail.getAndSet(fail.get() + 1);
                    log.info("飞行类型错误，{}", mode);
                    continue a;
                }
                java.time.ZonedDateTime zonedDateTime = startTime.atZone(ZoneId.systemDefault());
                long timestamp = zonedDateTime.toInstant().toEpochMilli();
                long systemTime = System.currentTimeMillis();
                if (timestamp < systemTime) {
                    fail.getAndSet(fail.get() + 1);
                    log.info("起飞时间必须大于当前时间，{}", startTimeStr.trim());
                    continue a;
                }

                LocalDateTime createTime = LocalDateTime.now();
                //    Task task = new Task();
                task.setName(taskName);
                task.setAircraftId(Math.toIntExact(airplaneId));
                task.setStartTime(startTime);
                task.setMode(mode);
                task.setCreateTime(createTime);
                task.setUpdateTime(createTime);
                task.setSetttings(settingsForPointList);
                task.setAuthorName(loginNameForToken);
                task.setAuthorId(Math.toIntExact(userIdForToken));
                task.setStartId(startId);
                task.setDestinationId(destinationId);
                tasks.add(task);
                success.getAndSet(success.get() + 1);
            }
        }

        String key = "batch:" + userIdForToken;
        redisUtil.set(key, tasks);
        res.put("success", success.get());
        res.put("fail", fail.get());
        res.put("redisKey", key);
        return res;
    }

    private List<TaskVO> getTaskVoList(List<Task> tasks) {
        List<TaskVO> taskVOS = new ArrayList<>();
        for (int i = 0; i < tasks.size(); i++) {
            TaskVO taskVO = new TaskVO();
           // System.err.println("****" + tasks.get(i).getId());
            taskVO.setTaskName(tasks.get(i).getName());
            String setttings = tasks.get(i).getSetttings()
                    .replaceAll("\n", "")
                    .replaceAll("\r", "")
                    .replaceAll("\t", "");
            List<String> names = new ArrayList<>();
            if (StringUtils.isEmpty(setttings)) {
                continue;
            }

            com.alibaba.fastjson2.JSONArray jsonArray = JSON.parseArray(setttings);

            for (int i1 = 0; i1 < jsonArray.size(); i1++) {
                Object o1 = jsonArray.get(i1);
                com.alibaba.fastjson2.JSONObject o = JSON.parseObject(o1.toString());
                //JSONObject o = (JSONObject) jsonArray.get(i1);
                if (i1 == 0) {//出发点
                    taskVO.setStartPointName(o.getString("name"));
                } else if (i1 == jsonArray.size() - 1) {
                    taskVO.setDestinationName(o.getString("name"));
                } else {
                    names.add(o.getString("name"));
                }
            }
            taskVO.setId(tasks.get(i).getId());
            taskVO.setTransitPointsName(StringUtils.join(names, "|"));
            taskVO.setMode(tasks.get(i).getMode());
            Result list = aircraftService.list(0, 1, null, null, tasks.get(i).getAircraftId());
            PageRes<Aircraft> data = (PageRes<Aircraft>) list.getData();
            taskVO.setStartTime(TimeUtils.getDateTime(tasks.get(i).getStartTime()));
            List<Aircraft> rows = data.getRows();
            try {
                Aircraft aircraft = rows.get(0);
                taskVO.setAirplaneName(aircraft.getAirplaneName());
            } catch (Exception e) {
                throw new CustomException("获取飞行器失败");
            }
            //获取轨迹信息
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("task_id", tasks.get(i).getId());

            long start = System.currentTimeMillis();
            JSONObject jo = HttpUtils.get(CST.URL + "/uam/route/track/detail", jsonObject);

            long end = System.currentTimeMillis();
            long time = end - start;
            if (jo != null) {
                JSONArray track = jo.getJSONArray("track");
                taskVO.setTrack(track);
            }
            taskVOS.add(taskVO);

        }
        return taskVOS;
    }
}

